package com.wei.czz.framework.rabbitMQ.listener.roleSpace;

import com.wei.czz.common.constant.EntityConstant;
import com.wei.czz.common.constant.RedisConstant;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.admin.userRole.RelationModeEnum;
import com.wei.czz.common.enums.rabbitMQ.MqEnum;
import com.wei.czz.common.utils.CopyUtils;
import com.wei.czz.framework.admin.entity.RoleGroupEntity;
import com.wei.czz.framework.admin.entity.UserRoleEntity;
import com.wei.czz.framework.admin.entity.UserRoleGroupEntity;
import com.wei.czz.framework.admin.service.RoleGroupService;
import com.wei.czz.framework.admin.service.UserRoleGroupService;
import com.wei.czz.framework.admin.service.UserRoleService;
import com.wei.czz.framework.rabbitMQ.message.roleSpace.RoleSpaceRoleUpdateMessage;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2024-12-13 14:15:17
 * className: RoleSpaceRoleQueueListener
 * version: 1.0
 * description:
 */
@Component
@AllArgsConstructor
public class RoleSpaceRoleQueueListener {

    private static final Logger log = LoggerFactory.getLogger(RoleSpaceRoleQueueListener.class);

    private final RoleGroupService roleGroupService;

    private final UserRoleGroupService userRoleGroupService;

    private final UserRoleService userRoleService;

    private final RedissonClient redissonClient;

    /**
     * 角色授权组关联角色变更消息监听方法
     */
    @RabbitListener(queues = { MqEnum.Queue.ROLE_SPACE_ROLE })
    public void roleSpaceRoleUpdateMessage(RoleSpaceRoleUpdateMessage updateMessage) {
        log.info("开始角色授权组关联角色变更消息处理。{}", updateMessage);

        String lockKey = RedisConstant.STRING + EntityConstant.ROLE_SPACE + RedisConstant.SPLIT +
                updateMessage.getMasterId();
        RLock lock = redissonClient.getLock(lockKey);
        // 加锁60秒
        lock.lock(60, TimeUnit.SECONDS);

        try {

            if (CommonEnum.ZERO.getValue().equals(updateMessage.getOptType())) {
                /*
                    新增
                 */
                this.saveUserRole(updateMessage.getMasterId(), updateMessage.getRoleIdList());

            } else if (CommonEnum.ONE.getValue().equals(updateMessage.getOptType())) {
                /*
                    删除
                 */
                this.deleteUserRole(updateMessage.getMasterId(), updateMessage.getRoleIdList());
            }

        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

        log.info("角色授权组关联角色变更消息处理完成");
    }

    /**
     * 保存用户关联角色
     * @param id         角色授权组主键
     * @param roleIdList 角色主键列表
     */
    private void saveUserRole(Long id, List<Long> roleIdList) {

        /*
            获取角色授权组关联用户
         */
        List<UserRoleGroupEntity> userRoleGroupList = userRoleGroupService.findList(Collections.singletonList(id),
                null, CommonEnum.ZERO.getValue());
        if (userRoleGroupList.isEmpty()) {
            log.info("角色授权组关联用户为空");
            return;
        }
        // 收集用户主键
        List<Long> userIdList = CopyUtils.mapList(userRoleGroupList, UserRoleGroupEntity::getUserId);

        /*
            获取用户关联角色
         */
        List<UserRoleEntity> userRoleList = userRoleService.findUserRoleList(userIdList, null,
                Collections.singletonList(RelationModeEnum.ROLE_SPACE.getValue()));
        // 用户与角色映射
        Map<Long, Set<Long>> userRoleMap = userRoleList.stream().collect(
                Collectors.groupingBy(
                        UserRoleEntity::getUserId,
                        Collectors.mapping(UserRoleEntity::getRoleId, Collectors.toSet())
                )
        );

        Date date = new Date();

        List<UserRoleEntity> saveUserRoleList = userRoleGroupList.stream()
                .flatMap(userRoleGroup -> {
                    return CopyUtils.mapList(roleIdList, roleId -> {
                                UserRoleEntity userRole = new UserRoleEntity();
                                userRole.setUserId(userRoleGroup.getUserId())
                                        .setRoleId(roleId)
                                        .setRelationMode(RelationModeEnum.ROLE_SPACE.getValue())
                                        .setDeleteStatus(CommonEnum.ZERO.getValue())
                                        .setUpdateTime(date)
                                        .setUpdateUser(StringUtils.EMPTY)
                                        .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                                        .setCreateTime(date)
                                        .setCreateUser(StringUtils.EMPTY)
                                        .setCreateUserId(CommonEnum.ZERO.getLongValue());

                                return userRole;
                            }).stream();
                })
                .filter(userRole -> {
                    // 获取用户关联角色（通过角色授权组关联角色）
                    Set<Long> roleIdSet = userRoleMap.get(userRole.getUserId());
                    if (Objects.isNull(roleIdSet)) {
                        // 角色主键集合为空，则说明用户可以关联该角色
                        return true;
                    }
                    // 判断用户已关联角色是否包含遍历到的角色，不包含则需要添加
                    return !roleIdSet.contains(userRole.getRoleId());
                })
                .collect(Collectors.toList());
        log.info("新增用户关联角色数据条数：{}", saveUserRoleList.size());
        if (!saveUserRoleList.isEmpty()) {
            /*
                保存用户关联角色
             */
            userRoleService.batchSave(saveUserRoleList);
        }
    }

    /**
     * 删除用户关联角色
     * @param id         角色授权组主键
     * @param roleIdList 角色主键列表
     */
    private void deleteUserRole(Long id, List<Long> roleIdList) {

        /*
            获取角色授权组关联用户
         */
        List<UserRoleGroupEntity> userRoleGroupList = userRoleGroupService.findList(Collections.singletonList(id),
                null, CommonEnum.ZERO.getValue());
        if (userRoleGroupList.isEmpty()) {
            log.info("【删除用户关联角色】角色授权组关联用户为空");
            return;
        }
        // 收集用户主键
        List<Long> userIdList = CopyUtils.mapList(userRoleGroupList, UserRoleGroupEntity::getUserId);

        /*
            获取用户关联的角色授权组
         */
        userRoleGroupList = userRoleGroupService.findList(null, userIdList,
                CommonEnum.ZERO.getValue());

        List<Long> idList = new ArrayList<>();
        Map<Long, List<Long>> userRoleGroupMap = new HashMap<>();
        for (UserRoleGroupEntity userRoleGroup : userRoleGroupList) {
            if (Objects.equals(userRoleGroup.getSpaceId(), id)) {
                // 排除当前正在操作的角色授权组
                continue;
            }
            // 收集角色授权组
            idList.add(userRoleGroup.getSpaceId());
            // 建立用户与角色授权组映射
            List<Long> _userIdList = userRoleGroupMap.computeIfAbsent(userRoleGroup.getSpaceId(), k -> new ArrayList<>());
            _userIdList.add(userRoleGroup.getUserId());
        }

        /*
            获取角色授权组关联角色
         */
        List<RoleGroupEntity> roleGroupList = roleGroupService.findList(idList, null, CommonEnum.ZERO.getValue());

        Map<Long, Set<Long>> userRoleMap = new HashMap<>();
        for (RoleGroupEntity roleGroup : roleGroupList) {
            // 获取角色授权组关联用户
            List<Long> _userIdList = userRoleGroupMap.get(roleGroup.getSpaceId());
            if (Objects.isNull(_userIdList)) {
                continue;
            }
            // 建立用户与角色映射
            for (Long userId : _userIdList) {
                Set<Long> roleIdSet = userRoleMap.computeIfAbsent(userId, k -> new HashSet<>());
                roleIdSet.add(roleGroup.getRoleId());
            }
        }

        /*
            获取用户关联角色（通过角色授权组关联的角色）
         */
        List<UserRoleEntity> userRoleList = userRoleService.findUserRoleList(userIdList, roleIdList,
                Collections.singletonList(RelationModeEnum.ROLE_SPACE.getValue()));
        if (userRoleList.isEmpty()) {
            log.info("【删除用户关联角色】用户通过角色授权组关联角色为空");
            return;
        }

        Date date = new Date();

        List<UserRoleEntity> updateUserRoleList = userRoleList.stream()
                .filter(userRole -> {
                    // 获取用户通过角色授权组关联的角色主键（已排除当前正在操作的角色授权组数据）
                    Set<Long> roleIdSet = userRoleMap.get(userRole.getUserId());
                    if (Objects.isNull(roleIdSet)) {
                        // 如果角色主键集合为空，则用户无需在关联该角色
                        return true;
                    }
                    // 如果用户没有通过角色授权组关联该角色，则用户无需在关联该角色
                    return !roleIdSet.contains(userRole.getRoleId());
                })
                .map(userRole -> {
                    UserRoleEntity updateUserRole = new UserRoleEntity();
                    updateUserRole.setId(userRole.getId())
                            .setDeleteStatus(CommonEnum.ONE.getValue())
                            .setUpdateTime(date)
                            .setUpdateUser(StringUtils.EMPTY)
                            .setUpdateUserId(CommonEnum.ZERO.getLongValue());
                    return updateUserRole;
                })
                .collect(Collectors.toList());
        log.info("更新用户关联角色数据条数：{}", updateUserRoleList.size());
        if (!updateUserRoleList.isEmpty()) {
            /*
                更新用户关联角色
             */
            userRoleService.batchUpdate(updateUserRoleList);
        }
    }
}
